# -*- coding: utf-8 -*-
# @Time    : 2021/4/15 17:06
# @Author  : Zhangrenjie
# @Email   : zhangrenjie1998@163.com
# @File    : 综合练习.py
# @Software: PyCharm

# 1、密码验证
# 2、列表去重并从大到小排序
# 3、如果在一个函数内部修改全局变量
# 4、如何跨模块共享全局变量
# 5、python数据类型有哪些
# 6、python中生成随机整数（1-10），随机小数（1-10），0-1之间小数的方法
# 7、python2与python3 的区别，列出5个
# 8、python中哪些是可变数据类型，哪些是不可变数据类型，为什么
# 9、统计字符串中每个单词出现的次数
# 10、给定一个字符串，找到字符串中第一个重复的字符
# 11、什么是pep8
# 12、python里如何赋值，深拷贝与浅拷贝的区别
# 13、简述python的内存管理机制
# 14、使用python实现冒泡排序
# 15、使用python实现快速排序
# 16、输出九九乘法表
# 17、重复接受用户的数据，如果是正整数就输出结果，否则一直输入
# 18、有两个列表[11,-3,4,5,2,1,8] , [9,3,4,2,6,-10] 把它们合并成一个列表，并且从小到大排序
# 19、a+=1 与 a=a+1 有什么区别

import random

# 2、列表去重并从大到小排序
# # 列表转换成集合再排序
# lst = [321, 213, 41, 32, 1, 321, 231, 32, 89]
# lst = set(lst)
# print(sorted(lst, reverse=True))

# 3、如果在一个函数内部修改全局变量
"""在函数内部相对应的变量去加上global"""

# 4、如何跨模块共享全局变量
# 方法一：模块调用
# 方法二：os.environ

# 5、python数据类型有哪些
'''
数字类型：
    整型 int
    浮点型 float
        浮点型的小数部分是使用二进制表示，因此他的准确性不高
        Decimal模块
    复数：n+xj real 实部 imag 虚部
容器类型
    字符串 str
    列表 list
    字典 dict
    元组 tuple
    集合 set
其他
    布尔型 bool
'''

# 6、python中生成随机整数（1-10），随机小数（1-10），0-1之间小数的方法
# rand_int = random.randint(1, 10)
# rand_float1 = random.uniform(1, 10)
# rand_float2 = random.random()
# print(rand_int, rand_float1, rand_float2)

# 7.python2与python3 的区别，列出5个
"""
python2                           python3
/ 结果是整型长整型                  / 结果是浮点型 input默认为int str要使用引号包裹
有长整型                             只有整型
模块与包中的__init__.py 必需要有      模块与包中的__init__.py 可有可无 
input默认为int str要使用引号包裹      input默认为str
bool型的True False不是关键字         bool型的True False是关键字
#-*-coding:utf-8-*-
"""

# 8、python中哪些是可变数据类型，哪些是不可变数据类型，为什么
"""
可变类型：列表，字典，集合
不可变类型：数字类型，字符串，元组，布尔
为什么：
可变：允许变量的值发生变化，即如果对变量进行append、+=等这种操作后，它改变了变量的值，
而不会新建一个对象，变量引用的对象的地址也不会变化(起始地址没变)；相同值的可变数据类型，
它们也是互相独立的对象，在不同的内存中，而不是像不可变数据类型那样只是增加了引用计数，
它们是实实在在的独立对象。

不可变：不允许变量的值发生变化，如果改变了变量的值，相当于是新建了一个对象新开辟一个内存区来存放该值；
而对于相同值的对象，通过增加引用计数，来表示引用方式的增加而实际上在内存中则只有一个对象（一个地址），
即这些引用都指向同一个地址
"""

# 9、统计字符串中每个单词出现的次数
# st = "There are moments in life when you miss someone so much that you just want to pick them from your dreams"
# words = st.split()
# for word in words:
#     print(f'{word}出现次数：{words.count(word)}')

# 10、给定一个字符串，找到字符串中第一个重复的字符
# 方法一
# st1 = "abcdeedebca"
# char = []
# index = []
# for i in st1:
#     if st1.count(i) > 1:
#         if i not in char:
#             st2 = st1[0:st1.find(i)] + st1[st1.find(i) + 1:]
#             num = st2.find(i)
#             index.append(num+1)
# index.sort()
# print(st1[index[0]])
# 方法二
# 进栈出栈
def match_char(s):
    ls = []
    for i in s:
        if i not in ls:
            ls.append(i)
        else:
            return i

msg = "wgebrtcxgrew"
print(match_char(msg))

# 11、什么是pep8
"""
Python代码样式指南
https://www.python.org/dev/peps/pep-0008/
"""

# 12、python里如何赋值，深拷贝与浅拷贝的区别
"""
赋值：
申请一个空间，将数据存放在此空间中
再申请为存放变量名的空间，里面存放的是所要赋值数据的引用地址

浅拷贝：是只拷贝第一层数据(地址)

深拷贝：是递归拷贝所有层的数据

操作不可变对象时，由于引用计数的特性，被拷贝的元素改变时，就相当于撕掉了原来的标签，
重新贴上新的标签一样，对于我们已拷贝的元素没有任何影响。因此在操作不可变对象时，
浅拷贝和深拷贝是没有区别的

总结：

1、由于 Python 内部引用计数的特性，对于不可变对象，浅拷贝和深拷贝的作用是一致的，
   就相当于复制了一份副本，原对象内部的不可变对象的改变，不会影响到复制对象。
2、浅拷贝的拷贝。其实是拷贝了原始元素的引用（内存地址），所以当拷贝可变对象时，
   原对象内可变对象的对应元素的改变，会在复制对象的对应元素上，有所体现。
3、深拷贝在遇到可变对象时，又在内部做了新建了一个副本。
   所以，不管它内部的元素如何变化，都不会影响到原来副本的可变对象
"""

# 13、简述python的内存管理机制
"""
内存管理机制是由引用计数、垃圾回收、内存池组成
引用计数：
    引用计数是一种非常高效的内存管理手段，
    当一个Python对象被引用时其引用计数增加1，
    当一个变量的引用失效后时则计数减1，
    一旦对象的引用技术为0，该对象可以被收回，对象占用的内存将被释放。
    优点：
        简单，实时性
    缺点：
        需要额外的空间维护引用计数，消耗资源
        最重要的问题是他不能解决对象的“循环引用“
垃圾回收：
    原理：当python的某个对象的引用计数将为0时，可以被垃圾回收
    gc机制：
        找到内存中的无用的垃圾资源，清除这些垃圾并把内存让出来给其他的对象使用
    分代回收：
        存活时间越久的对象，越不可能在后面的程序中变成垃圾
        python将所有的对象分为0，1，2三代
        所有的新建对象都时0代对象
        当某一代对象经历垃圾回收，仍然存活，那么它就被归入下一代对象
    标记清除：
        首先标记对象(垃圾检测)，然后清除垃圾(垃圾回收)。主要用于解决循环引用
        如果两个对象的引用计数都为 1，但是仅仅存在他们之间的循环引用，
        那么这两个对象都是需要被回收的，也就是说，它们的引用计数虽然表现为非 0，
        但实际上有效的引用计数为 0。所以先将循环引用摘掉，就会得出这两个对象的有效计数。
内存池：
        当创建大量消耗小内存的对象时，频繁调用new/malloc会导致大量的内存碎片，致使效率降低。
        内存池的作用就是预先在内存中申请一定数量的，大小相等的内存块留作备用，
        当有新的内存需求时，就先从内存池中分配内存给这个需求，不够之后再申请新的内存。
        这样做最显著的优势就是能够减少内存碎片，提升效率。
"""

# 14、使用python实现冒泡排序
"""冒泡排序是两个相邻的元素进行比较大小，大的放后面，小的放前面，每一轮可以判断一个最大的"""


# 方法一
# def bubble_sort(number):
#     n = len(number)
#     for item in range(n):
#         for i in range(len(number)-1-item):
#             if number[i] > number[i+1]:
#                 number[i], number[i+1] = number[i+1], number[i]
#
# # 方法二
# # def bubble_sort(number):
# #     for i in range(len(number) - 1):
# #         if number[i] > number[i + 1]:
# #             number[i], number[i + 1] = number[i + 1], number[i]
# #     number_copy = number[:]
# #     number_copy.sort()
# #     if number == number_copy:
# #         return
# #     else:
# #         bubble_sort(number)
# number = [11, -3, 4, 5, 2, 1, 8]
# bubble_sort(number)
# print(number)

# 15、使用python实现快速排序
def quicksort(number, i, j):
    if i >= j:
        return number
    key = number[i]
    low = i
    high = j
    while i < j:
        while i < j and number[j] >= key:
            j -= 1
        number[i], number[j] = number[j], number[i]
        while i < j and number[i] <= key:
            i += 1
        number[i], number[j] = number[j], number[i]
    quicksort(number, low, i - 1)
    quicksort(number, i + 1, high)
    return number


number = [30, 24, 5, 58, 18, 36, 12, 42, 39]
print(quicksort(number, 0, len(number) - 1))

# 16、输出九九乘法表
# for i in range(1, 10):
#     for j in range(1, i+1):
#         print(f'{i}*{j}={i*j}', end='\t')
#     print()

# 17、重复接受用户的数据，如果是正整数就输出结果，否则一直输入
# while True:
#     num = input("请输入正整数：")
#     try:
#         num = float(num)
#     except ValueError:
#         print(False)
#     else:
#         # 小数部分
#         char1 = str(num).split('.')[1]
#         # 整数部分
#         char2 = str(num).split('.')[0]
#         if int(char1) == 0 and int(char2) > 0:
#             break
#         else:
#             try:
#                 raise ValueError("正整数为1，2，3，4，……")
#             except ValueError as e:
#                 print(e)

# 18、有两个列表[11,-3,4,5,2,1,8] , [9,3,4,2,6,-10] 把它们合并成一个列表，并且从小到大排序
# lst1 = [11, -3, 4, 5, 2, 1, 8]
# lst2 = [9, 3, 4, 2, 6, -10]
# lst1.extend(lst2)
# lst1.sort()
# print(lst1)

# 19、a+=1 与 a=a+1 有什么区别
"""
对于可变对象，a += 1 直接在原内存地址上操作a = a + 1开辟新的内存操作
对于不可变对象，a += 1和a = a + 1都是在新开辟的空间操作
"""
# # 可变类型
# lst = [1, 2, 3, 4]
# print(lst, id(lst))
# lst += [1]
# print(lst, id(lst))
#
# lst = [1, 2, 3, 4]
# print(lst, id(lst))
# lst = lst + [1]
# print(lst, id(lst))
# # 不可变类型
# a = 1
# print(id(a))
# a += 1
# print(id(a))
# b = 1
# print(id(b))
# b = b + 1
# print(id(b))
